from django.db import models
from apps.users.models import User
from apps.courses.models import Course


class Enrollment(models.Model):
    STATUS_CHOICES = [
        ('enrolled', '已选课'),
        ('dropped', '已退选'),
        ('completed', '已完成'),
    ]

    student = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='学生', db_column='student_id')
    course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='课程', db_column='course_id')
    enrollment_date = models.DateTimeField(auto_now_add=True, verbose_name='选课时间')
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='enrolled', verbose_name='选课状态')

    # 成绩字段
    attendance_score = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True, null=True,
        verbose_name='考勤成绩',
        help_text='考勤成绩（0-100分）'
    )
    homework_score = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True, null=True,
        verbose_name='作业成绩',
        help_text='作业成绩（0-100分）'
    )
    midterm_score = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True, null=True,
        verbose_name='期中成绩',
        help_text='期中考试成绩（0-100分）'
    )
    final_score = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True, null=True,
        verbose_name='期末成绩',
        help_text='期末考试成绩（0-100分）'
    )
    total_score = models.DecimalField(
        max_digits=5, decimal_places=2, blank=True, null=True,
        verbose_name='总成绩',
        help_text='总成绩（0-100分）'
    )
    grade = models.CharField(
        max_length=5, blank=True, null=True,
        verbose_name='等级成绩',
        choices=[
            ('A', 'A (90-100)'),
            ('B', 'B (80-89)'),
            ('C', 'C (70-79)'),
            ('D', 'D (60-69)'),
            ('F', 'F (0-59)'),
        ],
        help_text='等级成绩'
    )

    # 成绩录入相关
    grade_entered_by = models.ForeignKey(
        User, on_delete=models.SET_NULL, blank=True, null=True,
        related_name='graded_enrollments', verbose_name='成绩录入教师',
        db_column='grade_entered_by'
    )
    grade_entered_at = models.DateTimeField(blank=True, null=True, verbose_name='成绩录入时间')

    # 备注
    remarks = models.TextField(blank=True, null=True, verbose_name='备注')

    # 时间戳
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        db_table = 'enrollments'
        verbose_name = '选课'
        verbose_name_plural = '选课'
        unique_together = ['student', 'course']
        indexes = [
            models.Index(fields=['student', 'status']),
            models.Index(fields=['course', 'status']),
            models.Index(fields=['enrollment_date']),
            models.Index(fields=['total_score']),
            models.Index(fields=['grade']),
        ]

    def __str__(self):
        return f"{self.student.real_name} - {self.course.course_name}"

    def save(self, *args, **kwargs):
        """保存时的额外处理"""
        super().save(*args, **kwargs)

        # 如果状态变化，更新课程的选课人数
        if self.pk:  # 确保是更新操作
            self.update_course_enrolled_count()

    def delete(self, *args, **kwargs):
        """删除时更新课程选课人数"""
        course = self.course
        super().delete(*args, **kwargs)
        # 更新课程选课人数
        course.enrolled_count = Enrollment.objects.filter(
            course=course,
            status='enrolled'
        ).count()
        course.save(update_fields=['enrolled_count'])

    def update_course_enrolled_count(self):
        """更新课程的选课人数"""
        if self.course_id:
            from django.db.models import F
            enrolled_count = Enrollment.objects.filter(
                course_id=self.course_id,
                status='enrolled'
            ).count()

            Course.objects.filter(id=self.course_id).update(
                enrolled_count=enrolled_count
            )

    @property
    def is_graded(self):
        """是否已录入成绩"""
        return self.total_score is not None

    @property
    def can_drop(self):
        """是否可以退课"""
        return self.status == 'enrolled' and not self.is_graded

    @property
    def gpa_points(self):
        """获取GPA点数"""
        if not self.grade:
            return 0

        grade_points = {
            'A': 4.0,
            'B': 3.0,
            'C': 2.0,
            'D': 1.0,
            'F': 0.0
        }
        return grade_points.get(self.grade, 0)

    def calculate_total_score(self, attendance_weight=0.2, homework_weight=0.2,
                              midterm_weight=0.3, final_weight=0.3):
        """
        根据各项成绩计算总成绩
        默认权重：考勤20%，作业20%，期中30%，期末30%
        """
        scores = [
            self.attendance_score,
            self.homework_score,
            self.midterm_score,
            self.final_score
        ]
        weights = [attendance_weight, homework_weight, midterm_weight, final_weight]

        # 检查是否所有成绩都已录入
        if all(score is not None for score in scores):
            total = sum(float(score) * weight for score, weight in zip(scores, weights))
            return round(total, 2)

        return None

    def auto_calculate_grade(self):
        """根据总成绩自动计算等级成绩"""
        if self.total_score is None:
            return None

        score = float(self.total_score)
        if score >= 90:
            return 'A'
        elif score >= 80:
            return 'B'
        elif score >= 70:
            return 'C'
        elif score >= 60:
            return 'D'
        else:
            return 'F'

    @classmethod
    def get_student_statistics(cls, student_id):
        """获取学生的选课统计信息"""
        enrollments = cls.objects.filter(student_id=student_id)

        total_enrolled = enrollments.filter(status='enrolled').count()
        total_completed = enrollments.filter(status='completed').count()
        total_dropped = enrollments.filter(status='dropped').count()

        # 计算总学分
        completed_enrollments = enrollments.filter(
            status__in=['enrolled', 'completed'],
            total_score__isnull=False
        ).select_related('course')

        total_credits = sum(e.course.credit_hours for e in completed_enrollments)

        # 计算GPA
        if completed_enrollments:
            total_grade_points = sum(
                e.gpa_points * e.course.credit_hours
                for e in completed_enrollments if e.grade
            )
            gpa = total_grade_points / total_credits if total_credits > 0 else 0
        else:
            gpa = 0

        # 计算通过率
        graded_enrollments = enrollments.filter(total_score__isnull=False)
        passed_enrollments = graded_enrollments.filter(
            models.Q(grade__in=['A', 'B', 'C', 'D']) | models.Q(total_score__gte=60)
        )
        pass_rate = (
            passed_enrollments.count() / graded_enrollments.count() * 100
            if graded_enrollments.count() > 0 else 0
        )

        return {
            'total_enrolled': total_enrolled,
            'total_completed': total_completed,
            'total_dropped': total_dropped,
            'total_credits': total_credits,
            'gpa': round(gpa, 2),
            'pass_rate': round(pass_rate, 2)
        }

    @classmethod
    def get_course_statistics(cls, course_id):
        """获取课程的选课统计信息"""
        enrollments = cls.objects.filter(course_id=course_id)

        total_students = enrollments.count()
        enrolled_students = enrollments.filter(status='enrolled').count()
        completed_students = enrollments.filter(status='completed').count()
        dropped_students = enrollments.filter(status='dropped').count()

        # 成绩统计
        graded_enrollments = enrollments.filter(total_score__isnull=False)
        avg_score = graded_enrollments.aggregate(
            avg=models.Avg('total_score')
        )['avg']

        # 等级分布
        grade_distribution = {}
        for grade_choice in cls._meta.get_field('grade').choices:
            grade_code = grade_choice[0]
            count = graded_enrollments.filter(grade=grade_code).count()
            grade_distribution[grade_code] = count

        return {
            'total_students': total_students,
            'enrolled_students': enrolled_students,
            'completed_students': completed_students,
            'dropped_students': dropped_students,
            'avg_score': round(avg_score, 2) if avg_score else 0,
            'grade_distribution': grade_distribution
        }